package utils

/*
 * string to number
 * number to string
 */
import (
	"errors"
	"fmt"
	"math"
	"regexp"
	"strconv"
	"strings"

)

func Itoa(i int) string {
	return strconv.Itoa(i)
}

// all kinds of string to number.
func Atoi(i string) (int, error) {
	return strconv.Atoi(i)
}
func AtoInt32(i string) (int32, error) {
	i = strings.TrimSpace(i)
	if v, err := strconv.ParseInt(i, 0, 64); err != nil {
		return 0, err
	} else {
		return int32(v), nil
	}
}
func AtoUint32(i string) (uint32, error) {
	i = strings.TrimSpace(i)
	if v, err := strconv.ParseUint(i, 0, 64); err != nil {
		return 0, err
	} else {
		return uint32(v), nil
	}
}
func AtoInt64(i string) (int64, error) {
	i = strings.TrimSpace(i)
	if v, err := strconv.ParseInt(i, 0, 64); err != nil {
		return 0, err
	} else {
		return v, nil
	}
}
func AtoUint64(i string) (uint64, error) {
	i = strings.TrimSpace(i)
	if v, err := strconv.ParseUint(i, 0, 64); err != nil {
		return 0, err
	} else {
		return v, nil
	}
}
func AtoFloat64(i string) (float64, error) {
	i = strings.TrimSpace(i)
	return strconv.ParseFloat(i, 64)
}

// str是不是一个数字型字符串
func IsNumber(str string) bool {
	str = strings.TrimSpace(str)
	_, err := strconv.ParseFloat(str, 64)
	if err == nil {
		return true
	}
	_, err = strconv.ParseInt(str, 0, 64)
	return err == nil
}

// AnyInt is a union type that includes int and uint variations.
type AnyInt interface {
	~int | ~int8 | ~int16 | ~int32 | ~int64 | ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~float32 | ~float64
}

func MaxMinIntT[T AnyInt](isMax bool) int64 {
	var zero T
	switch any(zero).(type) {
	case int:
		if isMax {
			return math.MaxInt
		} else {
			return math.MinInt
		}

	case int8:
		if isMax {
			return math.MaxInt8
		} else {
			return math.MinInt8
		}

	case int16:
		if isMax {
			return math.MaxInt16
		} else {
			return math.MinInt16
		}

	case int32:
		if isMax {
			return math.MaxInt32
		} else {
			return math.MinInt32
		}

	case int64:
		if isMax {
			return math.MaxInt64
		} else {
			return math.MinInt16
		}

	default:
		return 0
	}
}
func MaxMinUintT[T AnyInt](isMax bool) uint64 {
	var zero T
	switch any(zero).(type) {
	case uint:
		if isMax {
			return math.MaxUint
		} else {
			return 0
		}

	case uint8:
		if isMax {
			return math.MaxUint8
		} else {
			return 0
		}

	case uint16:
		if isMax {
			return math.MaxUint16
		} else {
			return 0
		}

	case uint32:
		if isMax {
			return math.MaxUint32
		} else {
			return 0
		}

	case uint64:
		if isMax {
			return math.MaxUint64
		} else {
			return 0
		}

	default:
		return 0
	}
}
func MaxMinFloat[T AnyInt](isMax bool) float64 {
	var zero T
	switch any(zero).(type) {
	case float32:
		if isMax {
			return math.MaxFloat32
		} else {
			return math.SmallestNonzeroFloat32
		}
	case float64:
		if isMax {
			return math.MaxFloat64
		} else {
			return math.SmallestNonzeroFloat64
		}
	default:
		return 0.0
	}
}

// ParseT parses a string as an digital type.
// max, min value return error.
func ParseT[T AnyInt](s string) (T, error) {
	var zero T
	s = strings.TrimSpace(s)

	switch any(zero).(type) {
	case int, int8, int16, int32, int64:
		if v, err := strconv.ParseInt(s, 0, 64); err != nil {
			return zero, err
		} else {
			if v > MaxMinIntT[T](true) || v < MaxMinIntT[T](false) {
				return zero, fmt.Errorf("max int error")
			}
			return T(v), nil
		}

	case uint, uint8, uint16, uint32, uint64:
		if v, err := strconv.ParseUint(s, 0, 64); err != nil {
			return zero, err
		} else {
			if v > MaxMinUintT[T](true) {
				return zero, fmt.Errorf("max uint error")
			}
			return T(v), nil
		}

	case float32, float64:
		if v, err := strconv.ParseFloat(s, 64); err != nil {
			return zero, err
		} else {
			if v > MaxMinFloat[T](true) || v < MaxMinFloat[T](false) {
				return zero, fmt.Errorf("max float error")
			}
			return T(v), nil
		}

	default:
		return zero, errors.New("unsupported type")
	}
}

// max of a and b.
func Max[T AnyInt](a, b T) T {
	if a > b {
		return a
	} else {
		return b
	}
}

// min of a and b.
func Min[T AnyInt](a, b T) T {
	if a > b {
		return b
	} else {
		return a
	}
}

// unicode to utf8.
func UnicodeToUTF8(input string) (string, error) {
	// 正则表达式匹配 {U+xxxx} 格式的 Unicode 代码点
	re := regexp.MustCompile(`\{U\+([0-9A-Fa-f]+)\}`)

	// 替换所有匹配的 Unicode 代码点
	output := re.ReplaceAllStringFunc(input, func(match string) string {
		// 提取代码点
		codePointStr := re.FindStringSubmatch(match)[1]

		// 将代码点转换成整数
		codePoint, err := strconv.ParseInt(codePointStr, 16, 32)
		if err != nil {
			return match
		}

		// 将整数转换成字符
		return string(rune(codePoint))
	})
	return output, nil
}
